using System;
using System.ComponentModel;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;

namespace Skywave.Windows.Forms
{
    public partial class ProgressiveBackgroundWorker : Component
    {
        public event RunWorkerCompletedEventHandler RunWorkerCompleted;
        public event DoWorkEventHandler DoWork;
        public event ProgressChangedEventHandler ProgressCustomAction;
        private Queue<object> qValues = new Queue<object>();
        private Queue<ProgressReportActions> qActions = new Queue<ProgressReportActions>();
        private Queue<int> qProgressIndexes = new Queue<int>();
        private Dictionary<int, ProgressInterface> progressInterfaces = new Dictionary<int, ProgressInterface>(2);
        private Dictionary<int, int> piParent = new Dictionary<int, int>(2);

        public ProgressiveBackgroundWorker()
        {
            InitializeComponent();
        }

        public ProgressiveBackgroundWorker(IContainer container)
        {
            container.Add(this);

            InitializeComponent();
        }


        public void AddProgressInterface(int progressIndex, ProgressInterface pi)
        {
            AddProgressInterface(progressIndex, pi, -1);
        }
        public void AddProgressInterface(int progressIndex, ProgressInterface pi, int parentProgressIndex)
        {
            if (progressIndex <= 0) return;
            if (progressInterfaces.ContainsKey(progressIndex)) return;
            progressInterfaces.Add(progressIndex, pi);
            if (progressInterfaces.ContainsKey(parentProgressIndex) && progressIndex != parentProgressIndex)
            {
                pi.Parent = progressInterfaces[parentProgressIndex];
                pi.Parent.Child = progressInterfaces[progressIndex];
                piParent.Add(progressIndex, parentProgressIndex);
            }
        }

        [System.ComponentModel.Browsable(false)]
        public bool CancellationPending
        {
            get { return myBW.CancellationPending; }
        }

        private object mTag;
        [System.ComponentModel.Browsable(false)]
        public object Tag
        {
            get { return mTag; }
            set { mTag = value; }
        }

        private System.Windows.Forms.Control mDisabledControlOnStart = null;
        public System.Windows.Forms.Control DisabledControlOnStart
        {
            get { return mDisabledControlOnStart; }
            set { mDisabledControlOnStart = value; }
        }

        private bool mEnforceVisibility = true;
        public bool EnforceVisibility
        {
            get { return mEnforceVisibility; }
            set { mEnforceVisibility = value; }
        }

        private void myBW_DoWork(object sender, DoWorkEventArgs e)
        {
            if (DoWork != null)
                DoWork(this, e);
        }

        private void myBW_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            ProgressReportActions curAction;
            object curValue;
            int curProgressIndex;
            lock (this)
            {
                curAction = qActions.Dequeue();
                curValue = qValues.Dequeue();
                curProgressIndex = qProgressIndexes.Dequeue();
            }
            ProgressInterface curPI = null;
            if (curAction != ProgressReportActions.CustomAction)
                if (progressInterfaces.ContainsKey(curProgressIndex))
                    curPI = progressInterfaces[curProgressIndex];
                else
                    return;
            switch (curAction)
            {
                case ProgressReportActions.ResetValue:
                    if (!piParent.ContainsValue(curProgressIndex))
                        curPI.SetValue(0);
                    break;
                case ProgressReportActions.SetMaximum:
                    if (!(curValue is int)) break;
                    curPI.SetMaximum((int)curValue);
                    break;
                case ProgressReportActions.SetValue:
                    if (!piParent.ContainsValue(curProgressIndex))
                    {
                        if (!(curValue is int)) break;
                        curPI.SetValue((int)curValue);
                    }
                    break;
                case ProgressReportActions.AddValue:
                    if (!piParent.ContainsValue(curProgressIndex))
                    {
                        if (!(curValue is int)) break;
                        if ((int)curValue == -1)
                            curPI.AddValue();
                        else
                            curPI.AddValue((int)curValue);
                    }
                    break;
                case ProgressReportActions.SetDescription:
                    curPI.SetDescription(curValue);
                    break;
                case ProgressReportActions.ProgressStyle:
                    curPI.SetStyle((System.Windows.Forms.ProgressBarStyle)curValue);
                    break;
                case ProgressReportActions.CustomAction:
                    if (ProgressCustomAction != null)
                        ProgressCustomAction(this, new ProgressChangedEventArgs(curProgressIndex, curValue));
                    break;
                case ProgressReportActions.ResetAll:
                    curPI.ResetAll();
                    break;
                default:
                    break;
            }
        }

        private void myBW_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if (RunWorkerCompleted != null)
                RunWorkerCompleted(this, e);
            if (mDisabledControlOnStart != null)
            {
                mDisabledControlOnStart.Enabled = true;
            }
            if (mEnforceVisibility)
            {
                foreach (ProgressInterface pi1 in progressInterfaces.Values)
                {
                    pi1.EndEnforceVisibility();
                }
            }
        }

        public void RunWorkerAsync()
        {
            if (mDisabledControlOnStart != null)
            {
                mDisabledControlOnStart.Enabled = false;
            }
            if (mEnforceVisibility)
            {
                foreach (ProgressInterface pi1 in progressInterfaces.Values)
                {
                    pi1.StartEnforceVisibility();
                }
            }
            myBW.RunWorkerAsync();
        }

        public void ReportProgress(int pIndex, object value, ProgressReportActions action)
        {
            lock (this)
            {
                qValues.Enqueue(value);
                qActions.Enqueue(action);
                qProgressIndexes.Enqueue(pIndex);
                myBW.ReportProgress(0, 0);
            }
        }
        public void ReportProgress(int pIndex, ProgressReportActions action)
        {
            ReportProgress(pIndex, -1, action);
        }
        public void ReportProgressBarStyle(int pIndex, System.Windows.Forms.ProgressBarStyle style)
        {
            ReportProgress(pIndex, style, ProgressReportActions.ProgressStyle);
        }

        [Browsable(false)]
        public bool IsBusy
        {
            get { return myBW.IsBusy; }
        }

        [Browsable(false)]
        public BackgroundWorker Worker
        {
            get { return myBW; }
        }

        public void CancelAsync()
        {
            myBW.CancelAsync();
        }
    }
}
